package com.sinodata.bsm.cicp.collector.mysql;

import java.sql.ResultSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.collector.AbstractJDBCCollector;
import com.sinodata.bsm.cicp.exception.CollectorException;
import com.sinodata.bsm.common.vo.ResPropertyValue;

public class MysqlServStatuCollector extends AbstractJDBCCollector {
    private final Logger logger = Logger.getLogger(MysqlServStatuCollector.class);
    private final Map<String, String> dbKeyMap = new HashMap<String, String>();

    public MysqlServStatuCollector() {
        MySQLUtil.initDbKeyMap(getDbServKeys(), getPropMeta(), dbKeyMap);
    }

    @Override
    public List<ResPropertyValue> collect(String ip) throws CollectorException {
        Map<String, String> dbMap = collectStatusFromDb(ip);
        List<ResPropertyValue> values = MySQLUtil.createPropValues(getDbKeyMap(), getPropMeta(), dbMap);
        dbMap.clear();
        return values;
    }

    /**
     * @param ip
     * @return
     * @throws CollectorException
     */
    private Map<String, String> collectStatusFromDb(String ip) throws CollectorException {
        String dbtype = getParamMap().get("DBType");
        String dbname = getParamMap().get("DBName");

        ResultSet rsVar = null;
        ResultSet rsStatus = null;
        Map<String, String> dbMap = new HashMap<String, String>();

        try {
            rsVar = this.getCachedResultSet(dbtype, ip, dbname, MySQLContants.VARIABLES);
            while (rsVar.next()) {
                dbMap.put(rsVar.getString(1).toLowerCase(), rsVar.getString(2) == null ? "" : rsVar.getString(2).trim().toLowerCase());
            }

            rsStatus = this.getCachedResultSet(dbtype, ip, dbname, "SHOW GLOBAL STATUS");

            long totalSQLCommandsExe = 0L;
            long commandExeTimes = 0L;

            while (rsStatus.next()) {
                dbMap.put(rsStatus.getString(1).toLowerCase(), rsStatus.getString(2) == null ? "" : rsStatus.getString(2).trim().toLowerCase());

                if (rsStatus.getString(1).toLowerCase().startsWith("com_")) {
                    try {
                        commandExeTimes = Long.parseLong(rsStatus.getString(2));
                    } catch (Exception e) {
                        logger.warn("Abnormal while getting the count of executing SQL in MySQL [" + rsStatus.getString(1) + ", " + rsStatus.getString(2) + "]", e);
                        commandExeTimes = 0;
                    }
                    totalSQLCommandsExe += commandExeTimes;
                }
            }
            dbMap.put("_TotalSQLCommandsExe".toLowerCase(), totalSQLCommandsExe + "");

        } catch (Exception ex) {
            logger.error("Collect mysql(" + ip + ") information error", ex);
            throw new CollectorException("Collect mysql(" + ip + ") information error", ex);
        }

        return dbMap;
    }

    @Override
    public String[] getParamMeta() {
        return new String[] { "DBType", "DBName" };
    }

    @Override
    public String[] getPropMeta() {
        return new String[] { "CurrentConns", "CurrentActiveConns", "TotalConns", "TotalReceiveDataSize", "TotalSendDataSize", "TotalSQLCommandsExe", "TotalExcepInteruptConns", "TotalFailedRequConns", "QueryCacheSize", "FreeQueryCache", "QueryCacheHitNum", "QueryCacheMissedNum", "IndexCacheBlockSize", "UnusedIndexCacheBlockSize", "UsedIndexCacheBlock", "ThreadPoolCapacity", "ThreadPoolThreads", "SortCacheSize", "SortRows", "SortMergeTimes", "KeyBufferSize", "ReadBufferSize", "MaxConnections", "LogErrorPath" };
    }

    private String[] getDbServKeys() {
        return new String[] { "threads_connected", "threads_running", "connections", "bytes_received", "bytes_sent", "_TotalSQLCommandsExe", "aborted_clients", "aborted_connects", "query_cache_size", "qcache_free_memory", "qcache_hits", "qcache_not_cached", "key_cache_block_size", "key_blocks_unused", "key_blocks_used", "thread_cache_size", "threads_cached", "sort_buffer_size", "sort_rows", "sort_merge_passes", "Key_buffer_size", "Read_buffer_size", "Max_connections", "log_error" };
    }

    /**
     * @return the dbKeyMap
     */
    public Map<String, String> getDbKeyMap() {
        return dbKeyMap;
    }

    /**
     * @param dbKeyMap
     *            the dbKeyMap to set
     */
    public void setDbKeyMap(String propMeta, String dbKey) {
        this.dbKeyMap.put(propMeta, dbKey);
    }
}
